/*
* Copyright 2011 Pavel Kozhin 
*
* Licensed under the Apache License, Version 2.0 (the "License"); 
* you may not use this file except in compliance with the License. 
* You may obtain a copy of the License at 
* 
* http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software 
* distributed  under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
* See the License for the specific language governing permissions and 
* limitations under the License.
*
* Author: Pavel Kozhin.
*/
package org.etherframework.mediator
{
	import flash.display.DisplayObject;
	import flash.events.Event;
	import flash.utils.Dictionary;
	
	import mx.core.IVisualElement;
	import mx.events.FlexEvent;
	import mx.managers.ILayoutManagerClient;
	
	import org.etherframework.IEther;
	import org.etherframework.common.IContractual;
	import org.etherframework.core.bridge.IBridgeFacades;
	import org.etherframework.core.bridge.ObjectController;
	import org.etherframework.core.common.ether_internal;
	
	[ExcludeClass]
	public final class MediatorController extends ObjectController
	{
		private var _target:IMediator;
		private var _view:DisplayObject;
		private var _activator:Activator;
		private var _views:Dictionary;
		private var _registered:Boolean;
		
		private var _completed:Boolean;
		private var _inited:Boolean;
		private var _attached:Boolean;
		
		public function MediatorController(target:IMediator, view:DisplayObject, 
										   ether:IEther, facade:IBridgeFacades, 
										   views:Dictionary)
		{
			super(target, ether, facade);
			
			_target = target;
			_view = view;
			_views = views;
		}
		
		// TODO: Refactor initialization and registration.
		override public function initialize():void
		{
			if (_views[_view])
				return;
			
			_views[_view] = this;
			
			super.initialize();
			
			if (_target is Mediator)
			{
				Mediator(_target).ether_internal::__init(ether, _view);
			}
			
			if (_target is IActivatable)
			{
				_activator = new Activator(_target as IActivatable, 
					_view as IVisualElement);
			}
			
			_view.stage ? initAttached() : initDetached();
		}
		
		// TODO: Refactor.
		override protected function register():void
		{
			if (_view.stage && !_registered && (_views[_view] == this))
			{
				super.register();
				
				_registered = true;
				
				if (_view is IContractual)
					IContractual(_view).contract = _target;
			}
		}
		
		override public function destroy():void
		{
			super.destroy();
			
			_view.removeEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler);
			_view.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			_view.removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
			_view.removeEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
			
			if (_activator)
				_activator.destroy();
			
			if (_views[_view] == this)
				delete _views[_view];
			
			_target = null;
			_view = null;
			_views = null;
			_activator = null;
		}
		
		private function initDetached():void
		{
			_view.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
			
			if (_view is ILayoutManagerClient && !ILayoutManagerClient(_view).initialized)
			{
				_view.addEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler, false, 0, true);
				_view.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
			}
		}
		
		private function initAttached():void
		{
			if (_view is ILayoutManagerClient && !ILayoutManagerClient(_view).initialized)
			{
				_view.addEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler, false, 0, true);
				_view.addEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler, false, 0, true);
			}
			
			commitAdded();
		}
		
		private function preinitializeHandler(event:FlexEvent):void
		{
			if (destroyed)
				return;
			
			_view.removeEventListener(FlexEvent.PREINITIALIZE, preinitializeHandler);
			
			commitInit();
		}
		
		private function creationCompleteHandler(event:FlexEvent):void
		{
			if (destroyed)
				return;
			
			_view.removeEventListener(FlexEvent.CREATION_COMPLETE, creationCompleteHandler);
			
			commitComplete();
		}
		
		private function addedToStageHandler(event:Event):void
		{
			if (destroyed)
				return;
			
			commitAdded();
		}
		
		private function removedFromStageHandler(event:Event):void
		{
			if (destroyed)
				return;
			
			_attached = false;
			ether.destroy();
			
			if (destroyed)
				return;
			
			_view.addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler, false, 0, true);
			_view.removeEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
		}
		
		private function commitInit():void
		{
			if (destroyed || _inited || !_view.stage)
				return;
			
			_inited = true;
			_target.initiate();
		}
		
		private function commitComplete():void
		{
			if (destroyed || _completed || !_view.stage)
				return;
			
			commitInit();
			
			_completed = true;
			_target.complete();
			
			if (_activator)
			{
				if (_target is ILazyActivatable)
				{
					_activator.enabled = false;
					ILazyActivatable(_target).activator = _activator;
				}
				_activator.initialize();
			}
		}
		
		private function commitAdded():void
		{
			if (destroyed || _attached || !_view.stage)
				return;
			
			_attached = true;
			_view.removeEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
			_view.addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler, false, 0, true);
			
			if (detached)
			{
				attach();
				detached = false;
			}
			
			if (!_registered)
			{
				register();
			}
			
			if (!(_view is ILayoutManagerClient) || 
				((_view is ILayoutManagerClient) && 
					ILayoutManagerClient(_view).initialized))
			{
				commitInit();
				commitComplete();
			}
		}
	}
}